package gee

import (
	"fmt"
	"net/http"
	"os"
	"strings"
)

// 定义路由表
type Router struct {
	// 根据请求方式（POST,PUT,GET...）划分成多个前缀树 -- （因为不同的请求方式 url可以一样）
	roots map[string]*node
}

/**
 * @Author: yang
 * @Description：路由--创建路由
 * @Date: 2021/11/4 17:52
 */
func newRouter() *Router {
	return &Router{
		roots: make(map[string]*node),
	}
}

/**
 * @Author: yang
 * @Description：路由--根据 “/” 分割路由地址
 * @Date: 2021/11/5 16:47
 */
func parsePattern(pattern string) []string {
	vs := strings.Split(pattern, "/")

	parts := make([]string, 0)
	for _, item := range vs {
		if item != "" {
			parts = append(parts, item)
			if item[0] == '*' {
				break
			}
		}
	}
	return parts
}

/**
 * @Author: yang
 * @Description：路由--设置路由表
 * @Date: 2021/11/4 17:30
 */
func (r *Router) addRoute(method string, pattern string, handler HandlerFunc) {
	// 根据 “/” 将路由分割成多个节点
	parts := parsePattern(pattern)

	// 初始化路由树--前缀树
	_, ok := r.roots[method]
	if !ok {
		r.roots[method] = &node{}
	}

	// 生成路由树--前缀树
	r.roots[method].insert(pattern, parts, 0, handler)
}

/**
 * @Author: yang
 * @Description：路由--获取节点
 * @Date: 2021/11/5 16:46
 */
func (r *Router) getRoute(method string, path string) (*node, map[string]string) {

	// 根据 “/” 将路由分割成多个节点
	searchParts := parsePattern(path)

	// 初始化params，保存url中参数值
	params := make(map[string]string)
	root, ok := r.roots[method]

	if !ok {
		return nil, nil
	}

	// 递归寻找叶子节点
	n := root.search(searchParts, 0)

	if n != nil {
		parts := parsePattern(n.pattern)
		for index, part := range parts {
			if part[0] == ':' {
				params[part[1:]] = searchParts[index]
			}
			if part[0] == '*' && len(part) > 1 {
				params[part[1:]] = strings.Join(searchParts[index:], "/")
				break
			}
		}
		return n, params
	}

	return nil, nil
}

// 请求回调函数执行
func (r *Router) handle(c *Context) {
	n, params := r.getRoute(c.Method, c.Path)
	if n != nil {
		c.Params = params
		// 请求回调放到 回调操作集合中
		c.handlers = append(c.handlers, n.handler)
	} else {
		// 定义个404的 handler
		c.handlers = append(c.handlers, func(context *Context) {
			c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
		})
	}

	// 访问日志 Middleware
	c.handlers = append(c.handlers, func(context *Context) {
		method := context.Method
		path := context.Path
		code := context.StatusCode
	_:
		fmt.Fprintf(os.Stderr, "[GIN-debug] %-6s %-25s --> [G%d] \n ", method, path, code)
	})

	// 循环执行 回调集合
	c.Next()
}
